package com.cloudfun.campusshare.service.impl;

import cn.hutool.core.util.StrUtil;
import com.cloudfun.campusshare.common.constant.KjtAuditStatus;
import com.cloudfun.campusshare.common.constant.KjtPayProductCode;
import com.cloudfun.campusshare.common.constant.KjtWithdrawStatus;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.cloudfun.campusshare.common.constant.*;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.dto.kjt.KjtSubMerchantWithdrawalCashReqDTO;
import com.cloudfun.campusshare.common.model.dto.kjt.KjtSubMerchantWithdrawalCashRespDTO;
import com.cloudfun.campusshare.common.model.vo.*;
import com.cloudfun.campusshare.common.response.PageResult;
import com.cloudfun.campusshare.common.security.AuthenticationHolder;
import com.cloudfun.campusshare.entity.*;
import com.cloudfun.campusshare.repo.*;
import com.cloudfun.campusshare.service.*;
import com.cloudfun.campusshare.util.*;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : zhangyongjie
 * @version : 1.0
 * @createTime : 2020/6/2 14:16
 * @description :
 */
@Service
@Slf4j
public class CashAdvanceServiceImpl extends CreatorPersistenceService implements CashAdvanceService {
    @Resource
    private CashAdvanceEntityRepo cashAdvanceEntityRepo;
    @Resource
    private DailyBalanceAccountEntityRepo dailyBalanceAccountEntityRepo;
    @Autowired
    private UserRelService userRelService;
    @Autowired
    private EntityManager entityManager;
    @Resource
    private UserEntityRepo userEntityRepo;
    @Resource
    private AuthOrgEntityRepo authOrgEntityRepo;
    @Autowired
    private OrderNoGenUtil orderNoGenUtil;
    @Autowired
    private KjtSubMerchantService kjtSubMerchantService;

    @Autowired
    private WithdrawApplicationRepo withdrawApplicationRepo;

    @Autowired
    private KjtService kjtService;

    private DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");


    @Override
    protected Class<?> getEntityClass() {
        return CashAdvanceEntity.class;
    }

    @Override
    public CashAdvanceMainDataVO getGeneralData() {
        String currentId = AuthenticationHolder.getUserId();
        UserEntity rootUser = userRelService.getUserMerchant(currentId);
        Map map = cashAdvanceEntityRepo.computeHistoryAmount(rootUser.getId());
        CashAdvanceMainDataVO re = new CashAdvanceMainDataVO();
        re.setHistoryTotalAmount(Optional.ofNullable(map.get("historyAmount")).map(x -> AmountUtil.amountRoundStr((BigDecimal) x, 2)).orElse("0.00"));
        LocalDate lastEndDate = cashAdvanceEntityRepo.getLastEndDate(rootUser.getId());
        Map<String, String> kjtTotalWithdrawal = computeAvailable(lastEndDate, rootUser.getId(), PayPlatform.KJT_PAT);
        Map<String, String> wxTotalWithdrawal = computeAvailable(lastEndDate, rootUser.getId(), PayPlatform.WX_PAY);
        Double settlementAmount = Double.parseDouble(kjtTotalWithdrawal.getOrDefault("settlementAmount", "0.00"));
        settlementAmount += Double.parseDouble(wxTotalWithdrawal.getOrDefault("settlementAmount", "0.00"));
        re.setAvailableAmount(AmountUtil.amountRoundStr((int) (settlementAmount * 100), 2));
        return re;
    }

    @Override
    public void launchCashAdvance() {
        String currentId = AuthenticationHolder.getUserId();
        UserEntity rootUser = userRelService.getUserMerchant(currentId);
        LocalDate lastEndDate = cashAdvanceEntityRepo.getLastEndDate(rootUser.getId());
        AuthOrgEntity auth = authOrgEntityRepo.findByUserId(rootUser.getId());
        CashAdvanceEntity cashAdvanceEntity = new CashAdvanceEntity();
        if (Objects.isNull(lastEndDate)) {
            //如果之前没提现过
            cashAdvanceEntity.setBeginTime(dailyBalanceAccountEntityRepo.getEarlyBillDate(rootUser.getId()));
        } else if (CollectionUtil.isNotEmpty(cashAdvanceEntityRepo.findByMerchantIdAndStatus(rootUser.getId(), CashAdvanceStatus.IN_PROGRESSING))) {
            //如果已经有提现中的订单
            throw new BusinessException(Code.NOT_PASS_YET);
        } else {
            //如果最近一次提现日期晚于或者等于昨天
            if (!LocalDate.now().minusDays(1).isAfter(lastEndDate)) {
                throw new BusinessException(Code.REPEAT_ACTION);
            }
            cashAdvanceEntity.setBeginTime(lastEndDate.plusDays(1));
        }
        Map<String, String> kjtTotalWithdrawal = computeAvailable(lastEndDate, rootUser.getId(), PayPlatform.KJT_PAT);
        Map<String, String> wxTotalWithdrawal = computeAvailable(lastEndDate, rootUser.getId(), PayPlatform.WX_PAY);
        Double settlementAmount = Double.parseDouble(kjtTotalWithdrawal.getOrDefault("settlementAmount", "0.00"));
        settlementAmount += Double.parseDouble(wxTotalWithdrawal.getOrDefault("settlementAmount", "0.00"));
        //可提现金额为0元不能提现
        if (AmountUtil.strAmount2Int(settlementAmount.toString(), 100) == 0) {
            throw new BusinessException(Code.ERROR, "当前没有可提现的金额");
        }
        cashAdvanceEntity.setMerchantId(rootUser.getId());
        cashAdvanceEntity.setBelongMerchantName(rootUser.getEnterpriseName());
        cashAdvanceEntity.setBankAccount(auth.getBankAccount());
        cashAdvanceEntity.setBankAccountName(auth.getBankAccountName());
        cashAdvanceEntity.setBankName(auth.getDepositBank());
        //开户省市
        cashAdvanceEntity.setDepositPosition(auth.getBankProvince() + auth.getBankCity());
        //开户支行
        cashAdvanceEntity.setBelongForkBank(auth.getDepositSubBank());
        CashAdvanceEntity clone = cashAdvanceEntity.clone();
        withdrawalRecordGeneration(wxTotalWithdrawal, cashAdvanceEntity, PayPlatform.WX_PAY);
        withdrawalRecordGeneration(kjtTotalWithdrawal, clone, PayPlatform.KJT_PAT);
    }


    private void withdrawalRecordGeneration(Map<String, String> TotalWithdrawal, CashAdvanceEntity cashAdvanceEntity, PayPlatform payPlatform) {
        if (AmountUtil.strAmount2Int(TotalWithdrawal.get("settlementAmount"), 100) == 0) {
//            throw new BusinessException(Code.ERROR, "当前没有可提现的金额");
            log.info("{} 当前没有可提现的金额", payPlatform.name());
            return;
        }
        cashAdvanceEntity.setCashAdvanceNo(orderNoGenUtil.next4Advance("tx-", "TX_SUFFIX"));
        cashAdvanceEntity.setEndTime(LocalDate.now().minusDays(1));
        cashAdvanceEntity.setTotalAmount(AmountUtil.strAmount2Int(TotalWithdrawal.get("journalAmount"), 100));
        cashAdvanceEntity.setTotalDiscountAmount(AmountUtil.strAmount2Int(TotalWithdrawal.get("discountAmount"), 100));
//        cashAdvanceEntity.setTotalHandingFee(AmountUtil.strAmount2Int(compute.get("handingFee"), 2));
        cashAdvanceEntity.setTotalSettlementAmount(AmountUtil.strAmount2Int(TotalWithdrawal.get("settlementAmount"), 100));
        //计算手续费（总结算金额 * 6/1000）
        double rate = cashAdvanceEntity.getTotalSettlementAmount() * BaseConstant.HANDING_FEE_RATE;
        String s = String.valueOf(rate);
        cashAdvanceEntity.setTotalHandingFee(Integer.parseInt(s.substring(0, s.lastIndexOf("."))));
        //预计提现金额 (总结算金额-手续费）
        cashAdvanceEntity.setExpectAmount(cashAdvanceEntity.getTotalSettlementAmount() - cashAdvanceEntity.getTotalHandingFee());
        cashAdvanceEntity.setLaunchTime(LocalDateTime.now());
        cashAdvanceEntity.setStatus(CashAdvanceStatus.IN_PROGRESSING);
        cashAdvanceEntity.setPayPlatform(payPlatform);
        //当前处理人  先写死
        cashAdvanceEntity.setTransactorId("ff80808172117740017211a4a45a0000");
        cashAdvanceEntity.setTransactorName("超级管理员");
        cashAdvanceEntity.setHandleTime(LocalDateTime.now());
        cashAdvanceEntityRepo.save(cashAdvanceEntity);
    }

    @Override
    public PageResult queryCashAdvanceList(Pageable pageable, String keyword, Set<Integer> status, String startTime, String endTime) {
        Page<CashAdvanceEntity> all = cashAdvanceEntityRepo.findAll(assembleCondition(keyword, status, startTime, endTime), pageable);
        return new PageResult(all.getTotalElements(), toListVO(all.getContent()));
    }

    @Override
    public CashAdvanceDetailVO queryCashAdvanceDetail(String cashAdvanceId) {
        CashAdvanceEntity cashAdvanceEntity = cashAdvanceEntityRepo.findById(cashAdvanceId).orElseThrow(() -> new BusinessException(Code.NODATA));
        return singleSwitch(cashAdvanceEntity, CashAdvanceDetailVO.class);
    }

    @Override
    public PageResult getDailyBalanceData(Pageable pageable, String cashAdvanceId) {
        CashAdvanceEntity cashAdvanceEntity = cashAdvanceEntityRepo.findById(cashAdvanceId).orElseThrow(() -> new BusinessException(Code.NODATA));
        LocalDate beginTime = cashAdvanceEntity.getBeginTime();
        LocalDate endTime = cashAdvanceEntity.getEndTime();
        Page<DailyBalanceAccountEntity> page = dailyBalanceAccountEntityRepo.findAll(((root, query, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            predicates.add(criteriaBuilder.between(root.get("billDate"), beginTime, endTime));
            predicates.add(criteriaBuilder.equal(root.get("merchantId"), cashAdvanceEntity.getMerchantId()));
            if (cashAdvanceEntity.getPayPlatform() == PayPlatform.WX_PAY) {
                predicates.add(criteriaBuilder.or(root.get("payPlatform").isNull(), root.get("payPlatform").in(cashAdvanceEntity.getPayPlatform())));
            } else {
                predicates.add(criteriaBuilder.equal(root.get("payPlatform"), cashAdvanceEntity.getPayPlatform()));
            }
            Predicate[] preArr = new Predicate[predicates.size()];
            return criteriaBuilder.and(predicates.toArray(preArr));
        }), PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.by(Sort.Direction.DESC, "billDate")));
        return new PageResult(page.getTotalElements(), page.getContent().stream().map(x -> {
            DailyBalanceListVO copy = BeanCopyUtil.copy(x, DailyBalanceListVO.class, "journalAmount", "discountPrice", "settlementAmount");
            copy.setJournalAmount(AmountUtil.amountRoundStr(x.getJournalAmount(), 2));
            copy.setDiscountPrice(AmountUtil.amountRoundStr(x.getDiscountPrice(), 2));
            copy.setSettlementAmount(AmountUtil.amountRoundStr(x.getSettlementAmount(), 2));
            return copy;
        }).collect(Collectors.toList()));
    }

    @Override
    public List<DailyBalanceListVO> getDailyBalanceDataList(String cashAdvanceId) {
        CashAdvanceEntity cashAdvanceEntity = cashAdvanceEntityRepo.findById(cashAdvanceId).orElseThrow(() -> new BusinessException(Code.NODATA));
        LocalDate beginTime = cashAdvanceEntity.getBeginTime();
        LocalDate endTime = cashAdvanceEntity.getEndTime();
        List<DailyBalanceAccountEntity> all = dailyBalanceAccountEntityRepo.findAll(((root, query, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            predicates.add(criteriaBuilder.between(root.get("billDate"), beginTime, endTime));
            predicates.add(criteriaBuilder.equal(root.get("merchantId"), cashAdvanceEntity.getMerchantId()));
            if (cashAdvanceEntity.getPayPlatform() == PayPlatform.WX_PAY) {
                predicates.add(criteriaBuilder.or(root.get("payPlatform").isNull(), root.get("payPlatform").in(cashAdvanceEntity.getPayPlatform())));
            } else {
                predicates.add(criteriaBuilder.equal(root.get("payPlatform"), cashAdvanceEntity.getPayPlatform()));
            }
            Predicate[] preArr = new Predicate[predicates.size()];
            return criteriaBuilder.and(predicates.toArray(preArr));
        }));
        return all.stream().map(x -> {
            DailyBalanceListVO copy = BeanCopyUtil.copy(x, DailyBalanceListVO.class, "journalAmount", "discountPrice", "settlementAmount");
            copy.setJournalAmount(AmountUtil.amountRoundStr(x.getJournalAmount(), 100));
            copy.setDiscountPrice(AmountUtil.amountRoundStr(x.getDiscountPrice(), 100));
            copy.setSettlementAmount(AmountUtil.amountRoundStr(x.getSettlementAmount(), 100));
            return copy;
        }).collect(Collectors.toList());
    }

    @Override
    public AccountConfirmVO confirmAccount() {
        String userId = AuthenticationHolder.getUserId();
        log.info("当前用户id:{}", userId);
        UserEntity userMerchant = userRelService.getUserMerchant(userId);
        log.info("当前用户运营商用户:{}", JSON.toJSONString(userMerchant));
        AuthOrgEntity auth = authOrgEntityRepo.findByUserId(userMerchant.getId());
        AccountConfirmVO re = new AccountConfirmVO();
        re.setBankAccount(auth.getBankAccount());
        re.setBankAccountName(auth.getBankAccountName());
        re.setBelongForkBankName(auth.getDepositSubBank());
        log.info("帐号确认返回结果:{}", JSON.toJSONString(re));
        return re;
    }

    @Override
    public List<CashAdvanceCountVO> countGroupByStatus() {
        String userId = AuthenticationHolder.getUserId();
        UserEntity userMerchant = userRelService.getUserMerchant(userId);
        List<Map> list = cashAdvanceEntityRepo.countGroupByStatus(userMerchant.getId());
        List<CashAdvanceCountVO> results = list.stream().map(x -> {
            CashAdvanceCountVO re = new CashAdvanceCountVO();
            re.setCount(((BigInteger) x.get("count")).longValue());
            re.setStatus((String) x.get("status"));
            return re;
        }).collect(Collectors.toList());
        List<String> collect = results.stream().map(CashAdvanceCountVO::getStatus).collect(Collectors.toList());
        for (CashAdvanceStatus value : CashAdvanceStatus.values()) {
            if (!collect.contains(value.name())) {
                CashAdvanceCountVO cac = new CashAdvanceCountVO();
                cac.setStatus(value.name());
                cac.setCount(0L);
                results.add(cac);
            }
        }
        return results;
    }

    @Override
    @Transactional
    public void handleCashAdvanceRequest(CashAdvanceHandleVO cashAdvanceHandleVO) {
        if (CashAdvanceHandleType.HIT_BACK.equals(cashAdvanceHandleVO.getType()) && StringUtils.isBlank(cashAdvanceHandleVO.getDescription())) {
            throw new BusinessException(Code.ERROR, "驳回时请务必填写说明");
        }
        CashAdvanceEntity cashAdvanceEntity = cashAdvanceEntityRepo.findById(cashAdvanceHandleVO.getCashAdvanceId()).orElseThrow(() -> new BusinessException(Code.NODATA));
        cashAdvanceEntity.setHandleResult(cashAdvanceHandleVO.getType());
        cashAdvanceEntity.setDescription(cashAdvanceHandleVO.getDescription());
        cashAdvanceEntity.setTransactorId(AuthenticationHolder.getUserId());
        cashAdvanceEntity.setTransactorName(AuthenticationHolder.getUserAuth().getUsername());
        cashAdvanceEntity.setStatus(CashAdvanceHandleType.HIT_BACK == cashAdvanceHandleVO.getType() ? CashAdvanceStatus.FAIL : CashAdvanceStatus.SUCCESS);

        if (CashAdvanceHandleType.PASS == cashAdvanceHandleVO.getType() && PayPlatform.KJT_PAT == cashAdvanceEntity.getPayPlatform()) {
//            快捷通提现
            Optional<SubMerchantEntity> entityByUserId = kjtSubMerchantService.getEntityByUserId(cashAdvanceEntity.getMerchantId());
            if (entityByUserId.isPresent()) {
                WithdrawApplicationEntity withdrawApplicationEntity = new WithdrawApplicationEntity();
                withdrawApplicationEntity.setSubMerchantId(entityByUserId.get().getId());
                withdrawApplicationEntity.setUserId(entityByUserId.get().getUserId());
                withdrawApplicationEntity.setPayProductCode(entityByUserId.get().getCompanyOrPerson().equals(BankType.TO_B) ? KjtPayProductCode.TO_B : KjtPayProductCode.TO_C);
                withdrawApplicationEntity.setWithdrawalAmount(cashAdvanceEntity.getExpectAmount());
                withdrawApplicationEntity.setMemo("提现");
                withdrawApplicationEntity.setOutTradeNo(cashAdvanceEntity.getCashAdvanceNo());
                withdrawApplicationEntity.setStatus(KjtAuditStatus.P);
                withdrawApplicationEntity.setWithdrawTime(LocalDateTime.now());
                withdrawApplicationRepo.save(withdrawApplicationEntity);
                KjtSubMerchantWithdrawalCashReqDTO reqDTO = KjtSubMerchantWithdrawalCashReqDTO.builder()
                        .outTradeNo(withdrawApplicationEntity.getOutTradeNo())
                        .partnerUserId(entityByUserId.get().getId())
                        .identityId(entityByUserId.get().getIdentityId())
                        .bizProductCode("10210")
                        .payProductCode(withdrawApplicationEntity.getPayProductCode().getValue())
                        .withdrawalAmount(AmountUtil.amountRoundStr(withdrawApplicationEntity.getWithdrawalAmount(), 2))
                        .memo("提现")
                        .build();
                KjtSubMerchantWithdrawalCashRespDTO respDTO = kjtService.subMerchantWithdrawalCash(reqDTO);
                log.info("提现:{}", respDTO);
                if (respDTO.getStatus() == KjtAuditStatus.F) {
                    throw new BusinessException(Code.ERROR, StrUtil.format("快捷通提现失败:原因{}", respDTO.getFailReason()));
                }
            }
        }
        cashAdvanceEntityRepo.save(cashAdvanceEntity);
    }

    @Override
    public List<CashAdvanceListExportVO> exportCashAdvanceList(Set<String> ids, String keyword, Set<Integer> status,
                                                               String startTime, String endTime, Boolean all) {
        if (CollectionUtil.isNotEmpty(ids)) {
            return switchToListExportVO(cashAdvanceEntityRepo.findAllById(ids), CashAdvanceListExportVO.class);
        } else if (BooleanUtils.isTrue(all)) {
            return switchToListExportVO(cashAdvanceEntityRepo.findAll(assembleCondition("", null, "", "")), CashAdvanceListExportVO.class);
        } else {
            return switchToListExportVO(cashAdvanceEntityRepo.findAll(assembleCondition(keyword, status, startTime, endTime)), CashAdvanceListExportVO.class);
        }
    }

    @Override
    public CashAdvanceDetailExportVO exportCashAdvanceDetail(String cashAdvanceId) {
        CashAdvanceEntity cashAdvanceEntity = cashAdvanceEntityRepo.findById(cashAdvanceId).orElseThrow(() -> new BusinessException(Code.NODATA));
        return switchToListExportVO(Lists.newArrayList(cashAdvanceEntity), CashAdvanceDetailExportVO.class).get(0);
    }

    private <T extends CashAdvanceExportBaseVO> List<T> switchToListExportVO(List<CashAdvanceEntity> list, Class<T> target) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return list.stream().map(x -> {
            T copy = BeanCopyUtil.copy(x, target, "totalAmount", "totalDiscountAmount", "totalHandingFee",
                    "totalSettlementAmount", "expectAmount", "launchTime", "status", "beginTime", "endTime");
            copy.setTotalHandingFee(AmountUtil.amountRoundStr(x.getTotalHandingFee(), 2));
            copy.setTotalSettlementAmount(AmountUtil.amountRoundStr(x.getTotalSettlementAmount(), 2));
            copy.setExpectAmount(AmountUtil.amountRoundStr(x.getExpectAmount(), 2));
            copy.setLaunchTime(DateUtil.localDateToString(x.getLaunchTime()));
            copy.setStatus(x.getStatus().getMerchantMessage());
            if (target == CashAdvanceListExportVO.class) {
                CashAdvanceListExportVO re = (CashAdvanceListExportVO) copy;
                re.setBeginTime(x.getBeginTime().format(df));
                re.setEndTime(x.getEndTime().format(df));
                return (T) re;
            } else {
                CashAdvanceDetailExportVO re = (CashAdvanceDetailExportVO) copy;
                re.setAdvanceRange(x.getBeginTime().format(df) + "~" + x.getEndTime().format(df));
                return (T) re;
            }
        }).collect(Collectors.toList());
    }


    private <T extends BaseCashAdvanceVO> T singleSwitch(CashAdvanceEntity source, Class<T> target) {
        T copy = BeanCopyUtil.copy(source, target, "totalAmount", "totalDiscountAmount", "totalHandingFee", "totalSettlementAmount", "expectAmount");
        copy.setTotalAmount(AmountUtil.amountRoundStr(source.getTotalAmount(), 2));
        copy.setTotalDiscountAmount(AmountUtil.amountRoundStr(source.getTotalDiscountAmount(), 2));
        copy.setTotalHandingFee(AmountUtil.amountRoundStr(source.getTotalHandingFee(), 2));
        copy.setTotalSettlementAmount(AmountUtil.amountRoundStr(source.getTotalSettlementAmount(), 2));
        copy.setExpectAmount(AmountUtil.amountRoundStr(source.getExpectAmount(), 2));
        return copy;
    }

    private List<CashAdvanceListVO> toListVO(List<CashAdvanceEntity> list) {
        return list.stream().map(x -> singleSwitch(x, CashAdvanceListVO.class)).collect(Collectors.toList());
    }

    private Specification<CashAdvanceEntity> assembleCondition(String keyword, Set<Integer> status, String startTime, String endTime) {
        return ((root, query, criteriaBuilder) -> {
            String currentId = AuthenticationHolder.getUserId();
            UserEntity userMerchant = userRelService.getUserMerchant(currentId);
            List<Predicate> predicates = Lists.newArrayList();
            if (!AuthenticationHolder.isAdmin()) {
                predicates.add(criteriaBuilder.equal(root.get("merchantId"), userMerchant.getId()));
            }
            if (StringUtils.isNotBlank(keyword)) {
                List<Predicate> likes = Lists.newArrayList();
                likes.add(criteriaBuilder.like(root.get("cashAdvanceNo"), keyword));
                likes.add(criteriaBuilder.like(root.get("belongMerchantName"), keyword));
                likes.add(criteriaBuilder.like(root.get("creatorName"), keyword));
                Predicate[] likeArr = new Predicate[likes.size()];
                predicates.add(criteriaBuilder.or(likes.toArray(likeArr)));
            }

            if (CollectionUtil.isNotEmpty(status)) {
                predicates.add(root.get("status").in(status.stream().map(CashAdvanceStatus::getByCode).collect(Collectors.toList())));
            }

            if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime start = LocalDateTime.parse(startTime, df);
                LocalDateTime end = LocalDateTime.parse(endTime, df);
                predicates.add(criteriaBuilder.between(root.get("launchTime"), start, end));
            }
            Predicate[] preArr = new Predicate[predicates.size()];
            return criteriaBuilder.and(predicates.toArray(preArr));
        });
    }

    private Map<String, String> computeAvailable(LocalDate endDate, String merchantId, PayPlatform payPlatform) {
        StringBuilder sb = new StringBuilder("select sum(journal_amount)as journalAmount,sum(discount_price)as discountAmount" +
                ",sum(handing_fee) as handingFee,sum(settlement_amount) as settlementAmount from daily_balance_account where 1=1");
        sb.append(" and merchant_id=:merchantId");
        if (payPlatform == PayPlatform.WX_PAY) {
            sb.append(" and (pay_platform='WX_PAY' or pay_platform is null )");
        } else if (payPlatform == PayPlatform.KJT_PAT) {
            sb.append(" and pay_platform='KJT_PAT'");
        }
        if (!Objects.isNull(endDate)) {
            sb.append(" and bill_date > :billDate");
        }
        Query nativeQuery = entityManager.createNativeQuery(sb.toString());
        nativeQuery.setParameter("merchantId", merchantId);
        if (!Objects.isNull(endDate)) {
            nativeQuery.setParameter("billDate", endDate);
        }
        Object[] result = (Object[]) QueryUtil.getSingleResult(nativeQuery);
        Map<String, String> map = new HashMap<>();
        map.put("journalAmount", AmountUtil.amountRoundStr(Optional.ofNullable(result[0]).map(x -> (BigDecimal) x).orElse(BigDecimal.ZERO), 2));
        map.put("discountAmount", AmountUtil.amountRoundStr(Optional.ofNullable(result[1]).map(x -> (BigDecimal) x).orElse(BigDecimal.ZERO), 2));
        map.put("handingFee", AmountUtil.amountRoundStr(Optional.ofNullable(result[2]).map(x -> (BigDecimal) x).orElse(BigDecimal.ZERO), 2));
        map.put("settlementAmount", AmountUtil.amountRoundStr(Optional.ofNullable(result[3]).map(x -> (BigDecimal) x).orElse(BigDecimal.ZERO), 2));
        return map;
    }
}
